/* $Header: sigpath.c,v 2.4 02/04/25 13:22:35 przybyls Exp $ */

/***********************************************************************/
/*                                                                     */
/*                  Copyright Hewlett-Packard Co. 1991, 1992           */
/*                                                                     */
/***********************************************************************/

/***********************************************************************/
/* MODULE NAME: sigpath.c                                              */
/* ============                                                        */
/*                                                                     */
/* Author:        Lesley Freed                                         */
/*                                                                     */
/* MODULE PURPOSE: To process the data from the Signal DSP (Digital    */
/*                 Signal Processor) after every 100 Hz data transfer  */
/*                 during the 512 Hz interrupt.  The requirement       */
/*                 of this module is that it be fast.                  */
/*                                                                     */
/*                                                                     */
/***********************************************************************/


/*****************************/
/*   GLOBAL INCLUDE FILES    */
/*****************************/

#include <typedefs.h>
#include <error.h>
#include <exception.h>
#include <err_handler.h>
#include <p_wkfile.h>
#include <wkfile.h>
#include <ramps.h>
#include <zone_config.h>
#include <zone_status.h>
#include <status.h>
#include <sig_types.h>
#include <sigpath.h>
#include <dig_path.h>
#include <config.h>
#include <math.h>

/*****************************/
/*   LOCAL INCLUDE FILES     */
/*****************************/

#include <sig_digital.h>


/*****************************/
/*   GLOBAL VARIABLES        */
/*****************************/

#define DEBUG 0
#define uECD_DIG 0

#if DEBUG
/* REVISIT:  debug bunching */
   DIG_DATA Test_Out[5];
/* end of REVISIT */
#endif


/*****************************/
/*   EXTERNAL VARIABLES      */
/*****************************/

extern  const U_INT32   RANGE_REM_TABLE[];

/*****************************/
/*   LOCAL DEFINES           */
/*****************************/

/* Set signal run state to RUN_IN_PROGRESS.  This indicates that a start      */
/* marker has been sent.  If we are in RUN acquisition mode then set signal   */
/* acquisition to TRUE.                                                       */

#define SET_RUN_IN_PROGRESS()                                                  \
{                                                                              \
   pSignal->run_state = RUN_IN_PROGRESS;                                       \
   if (( Acq_Mode[pSignal->chan] == RUN ) ||                                   \
       ( Acq_Mode[pSignal->chan] == SGL ))                                     \
   {                                                                           \
      Acq_On[ pSignal->chan ] = TRUE;                                          \
   }                                                                           \
}

#define COPY_ARRAY(in,out,max)                                                 \
{                                                                              \
   for (i=0;i<max;i++)                                                         \
   {   out[i]=in[i]; }                                                         \
}

/* REVISIT: for uECD until we get analog path working */
U_INT32 uECD_In_Hi1, uECD_Out_Hi1;
U_INT32 uECD_In_Hi2, uECD_Out_Hi2;
U_INT32 aECD_In_Hi1, aECD_Out_Hi1; /* also for SIG1_FREEZE & SIG1_RESUME */
U_INT32 aECD_In_Hi2, aECD_Out_Hi2; /* also for SIG2_FREEZE & SIG2_RESUME */
U_INT8  hold_idx1                ; /* for SIG1_RESUME */
U_INT8  hold_idx2                ; /* for SIG2_RESUME */

/*****************************/
/*   DOCUMENTATION SECTION   */
/*****************************/

/* This module handles the signals in the signal path after they have been    */
/* processed by the detector DSP.  After it is done it sends the results of   */
/* it's processing it tranfers the results onto the appropriate consumer.     */
/* In the case of the digital signals they are sent on to be store in a       */
/* if acquisition is set to on.  The acquistion on/off state is dependent     */
/* upon the acquisition mode, the run state, and it can be set on or off      */
/* via the hostcommand system.  The following timing diagrams show how it is  */
/* handled.


1)  ACQ_MODE = RUN or SGL:

                    1________2             3_________________________5
 ACQ_ON ____________|        |_____________|                         |________

                    1________2                   4___________________5
 RUN_IN_PROGRESS____|        |___________________|                   |________


 pt 1:  the signal run state becomes RUN_IN_PROGRESS, acquisiton on is set to
        TRUE
 pt 2:  the signal run state becomes RUN_IDLE, acquisiton on is set to FALSE
 pt 3:  acquisiton on is set to TRUE by the hostcommand system
 pt 4:  the signal run state becomes RUN_IN_PROGRESS, acquisiton on is set to
        TRUE (note:  this has no effect since it was already set to TRUE)
 pt 5:  the signal run state becomes RUN_IDLE, acquisiton on is set to FALSE

2)  ACQ_MODE = RUN or SGL:

                    1________2
 ACQ_ON ____________|        |________________________________________________

                    1________________________________________________3
 RUN_IN_PROGRESS____|                                                |________

 pt 1:  the signal run state becomes RUN_IN_PROGRESS, acquisiton on is set to
        TRUE
 pt 2:  acquisiton on is set to FALSE by the hostcommand system
 pt 4:  the signal run state becomes RUN_IDLE, acquisiton on is set to FALSE
        (note:  this has no effect since it was already set to FALSE)

3)  ACQ_MODE = CON (continuous):

    In the case of CON mode, the data is sent only when the acqusition on is set
    to TRUE.  Acquistion on is set only through the hostcommand system.

*/



/*****************************/
/*   IMPLEMENT SECTION       */
/*****************************/

#ifndef mccabe
#pragma SECTION PROG=SysCode
#endif

/* This code should be in SysCode using Absolute Short Addressing */

/* A:  lower interpolation pt                             */
/* B:  upper interpolation pt                             */
/* x:  input data pt                                      */
/* y:  output data pt                                     */
/* a:  minimum input data pt                              */
/* b:  maximum input data pt                              */
/* b-a: range of input data, 2^14                         */
/*                                                        */
/* Calculate: y = A + (B-A) * (x-a)                       */
/*                    -----                               */
/*                    (b-a)                               */

U_INT32 LinUECD( const U_INT32 tbl[], INT32 x )
{
   U_INT16 i;
   INT32   B_A_diff,x_a_diff;
   U_INT32 A;

   /* x: the MS 24-bits from the uECD detector */

   /* Check for negative data.  We will clamp such data at zero */
   if (x<0)
   {
      return 0;
   }

   i = (U_INT32)x >> 14;   /* 2^14 table increment */

   /* Check for data exceeding the range of the table.  Although
      the signal data can theoretically be up to 2^24 we will
      only support data up to 2^21.  This should handle the
      expected full range of the input data.
   */
   if ( i > 1024 )
   {
      return tbl[1024];
   }

   /* Get the difference between two interpolation points, A, B */
   A        = tbl[i];
   B_A_diff = tbl[i+1]-A;

   /* Calculate the difference between the actual data point, x, */
   /* and the first entry in the table, x - a. We want this in   */
   /* units of 240 counts per display count, the same as the     */
   /* units of the table.                                        */

   x_a_diff = (U_INT32)x & 0x00003fff;

   /* Calculate (B-A)*(x-a) */
   x  = TblMult( B_A_diff,x_a_diff);

   /* Add the interpolated difference to the starting interpolation */
   /* point and return.                                             */
   return x + A;
}


/* This code should be in SysCode using Absolute Short Addressing */

/* A:  lower interpolation pt                             */
/* B:  upper interpolation pt                             */
/* x:  input data pt                                      */
/* y:  output data pt                                     */
/* a:  minimum input data pt                              */
/* b:  maximum input data pt                              */
/* b-a: range of input data, 2^14                         */
/*                                                        */
/* Calculate: y = A + (B-A) * (x-a)                       */
/*                    -----                               */
/*                    (b-a)                               */

U_INT32 LinLDID( const U_INT32 tbl[], INT32 x )
{
   U_INT16 i;
   INT32   B_A_diff,x_a_diff;
   U_INT32 A;

   /* x: the MS 24-bits from the uECD detector */

   /* Check for negative data.  We will clamp such data at zero */
   if (x<0)
   {
      return 0;
   }

   /* TEMPORARY: bypass linearization while determining linearization constants */
   return x;

   i = (U_INT32)x >> 22;   /* 2^14 table increment + use highest 10 bits */

   /* Check for data exceeding the range of the table.  Although
      the signal data can theoretically be up to 2^24 we will
      only support data up to 2^21.  This should handle the
      expected full range of the input data.
   */
   if ( i > 1024 )
   {
      return tbl[1024];
   }

   /* Get the difference between two interpolation points, A, B */
   A        = tbl[i];
   B_A_diff = tbl[i+1]-A;

   /* Calculate the difference between the actual data point, x, */
   /* and the first entry in the table, x - a. We want this in   */
   /* units of 240 counts per display count, the same as the     */
   /* units of the table.                                        */

   x_a_diff = (U_INT32)x & 0x00003fff;

   /* Calculate (B-A)*(x-a) */
   x  = TblMult( B_A_diff,x_a_diff);

   /* Add the interpolated difference to the starting interpolation */
   /* point and return.                                             */
   return x + A;
}


void DigitalSignalPath( void )
{
   U_INT16 i;           /* loop counter for data count */
   U_INT16 s_temp;
   U_INT16 s_dsp;
   INT32   *x;
   DIG48   sig;

   /* Check for invalid data count.  If so then report exception and do not   */
   /* process the data, we have a screwed up Dsp_In data structure.           */

   if (pSignal->dsp_data->sig_count > 5)
   {
      pSignal->dsp_data->sig_count = 0;           /* Do not output any data */
      SetNewException( INVALID_SIG_COUNT,0,0 );   /* Signal Data Fault      */
   }
   else
   {
/* if (pSignal->dsp_data->sig_count > 2) pSignal->dsp_data->sig_count = 2;  REMOVE */

      /* Process the digital data */
      for (i=1; i<=pSignal->dsp_data->sig_count; i++)
      {


        x = &pSignal->dsp_data->sig_out_hi[i-1];



        /* REVISIT: test for uECD */
        if ( pSignal->chan == SIGNAL1 )
        {
           uECD_In_Hi1 = *x;
        }
        else
        {
           uECD_In_Hi2 = *x;
        }
        /* End of REVISIT: test for uECD */



        /* REVISIT: for uECD development ... NO !!! Now aECD_In_HiX also used by FREEZE_SIGNAL rtt events !! */

        if ( pSignal->zero_attn_on_off & FREEZE_SIG_ON_MASK )
        {
           *x = ((pSignal->chan == SIGNAL1) ? uECD_Out_Hi1 : uECD_Out_Hi2 );
        }
        else
        {

           switch ( (BIT8)pSignal->sig_conv_mode )
           {
              case CONV_uECD_LIN:
                 switch ( pSignal->active_wkfile->rate )
                 {
                    /* The analog data and the digital data are the SAME for   */
                    /* the digital data rate of 100 Hz.  (See Theory of Oper-  */
                    /* ation of the 6890A Detector Signal Processing).         */
                    case RATE_200HZ:
                    case RATE_100HZ: *x = pSignal->conv_analog;
                                     break;

                    case RATE_50HZ:
                    case RATE_20HZ:  *x = LinUECD( UECD_TBL, *x);
                                     break;

                    default:         *x = LinUECD( UECD_TBL_ATN, *x);
                 }
                 pSignal->dsp_data->sig_out_lo[i-1] = 0;
                 break;

              case CONV_uECD_TEST:
                 /* Scale the data for the uECD to be in units of Hz.  The uECD */
                 /* board has units of 2.5 Hz/display count for unlinearized    */
                 /* data.                                                       */

                 *x = SignedQuadWordMultiplyDivide(*x, 32*25,33*10);
                 pSignal->dsp_data->sig_out_lo[i-1] = 0;
                 break;

           case CONV_LDID_LIN:
              switch ( pSignal->active_wkfile->rate )
              {
                 /* The analog data and the digital data are the SAME for   */
                 /* the digital data rate of 100 Hz.  (See Theory of Oper-  */
                 /* ation of the 6890A Detector Signal Processing).         */
                 case RATE_200HZ:
                 case RATE_100HZ: *x = pSignal->conv_analog;
                                  break;

                 case RATE_50HZ:
                 case RATE_20HZ:  *x = LinLDID( LDID_TBL, *x);
                                  break;

                 default:         *x = LinLDID( LDID_TBL_ATN, *x);
                                  break;
              }
              pSignal->dsp_data->sig_out_lo[i-1] = 0;
              break;

           case CONV_LDID_TEST:
              /* Scale the data for the LDID to be in units of pA.  The LDID  */
              /* board has units of ??????/display count for unlinearized     */
              /* data.                                                        */
/* REVISIT    *x = SignedQuadWordMultiplyDivide(*x, 32*25,33*10);
              pSignal->dsp_data->sig_out_lo[i-1] = 0;
*/
              break;

           default:             /* do nothing */
              break;
           }

           *((pSignal->chan == SIGNAL1) ? &uECD_Out_Hi1 : &uECD_Out_Hi2 ) = *x ;

        }



        /* REVISIT: for uecd debug *!  This moved up so as to also support FREEZE/RESUME RTT fns *************
              if ( pSignal->chan == SIGNAL1 )
              {
                 uECD_Out_Hi1 = *x;
              }
              else
              {
                 uECD_Out_Hi2 = *x;
              }
        !* End of REVISIT: for uecd debug ******************************************************************** */



        /* Process all the data points */
        DigitalSigPath((i-1));


      }
   }

   switch ( pSignal->run_state )
   {
      case NOT_IN_RUN:

         HandleStartSignal();
         HandleStopSignal();

         break;

      case START_PENDING:

         HandlePendingStartSignal();
         HandleStopSignal();
         HandleStartSignal();

         break;

      case RUN_IN_PROGRESS:

         HandleStopSignal();
         HandleStartSignal();

         break;
   }

   /* FINALLY, if data acquisition is turned on for this channel and data is  */
   /* available then output the Digital Data to the CompressAndStore Routine  */
   if ( pSignal->dsp_data->sig_count > 0 )
   {

      if ( Acq_On[ pSignal->chan ] )
      {

#if DEBUG
         COPY_ARRAY(pSignal->dig_data,Test_Out,pSignal->dsp_data->sig_count)
#endif

         CompressAndStore(pSignal->chan, (DIG48 *)&pSignal->dig_data[0],
                             pSignal->dsp_data->sig_count);

         /* See if we have gotten a STOP indication.  If we are in RUN or SGL */
         /* acquisition mode (that is, not in CON, continuous, mode) then set */
         /* acquisition off.                                                  */

         if ( ( Acq_Mode[pSignal->chan] != CON ) &&
              ( pSignal->dig_data[pSignal->dsp_data->sig_count-1].hi_long ==
                (INT32)STOP_SIGNAL_MARKER ) )
         {
            Acq_On[pSignal->chan] = FALSE;
         }
      }

   }
} /* end fn "DigitalSignalPath" */



/***********************************************************************/
/* FUNCTION: SigPath                                                   */
/* ========                                                            */
/*                                                                     */
/* PURPOSE: To take the data for the digital and analog outputs and    */
/*          apply the appropriate range, zero and filtering.           */
/*                                                                     */
/*          It will select the appropriate signal soure for both the   */
/*          digital and analog signal path.                            */
/*                                                                     */
/*          It will insert a START marker and start time or STOP       */
/*          marker in the digital data stream when appropriate.        */
/*                                                                     */
/* RETURNED VALUE: none                                                */
/*                                                                     */
/* GLOBALS USED:  pSignal:  ptr to Signal 1 or 2                       */
/*                                                                     */
/* LIMITATIONS:  This routine ASSUMES that the pointer pSignal,        */
/*               has been set to the appropriate Signal1 or 2          */
/*               by the calling function.                              */
/*                                                                     */
/***********************************************************************/

void SigPath(void)
{
        U_INT16 i;           /* loop counter for data count */
        U_INT16 s_temp;
        INT32   s_signal;

/* Analog Signal Path */

   /* First we need to get the signal data */

   s_temp = (U_INT8)pSignal->signal;                   /* Get the signal type */

   /* Check for detector type signal */
   if (s_temp <= (U_INT8)MAX_DET_SIGNAL_TYPE)
   {

      /* Get the data from the detector DSP */
      s_signal = pSignal->dsp_data->sig_out_100;

      /* REVISIT: for uECD development */
      if ( pSignal->chan == SIGNAL1 )
      {
         aECD_In_Hi1 = s_signal;
      }
      else
      {
         aECD_In_Hi2 = s_signal;
      }
      /* End of REVISIT: for uECD development */


      #if uECD_DIG
      if ( pSignal->sig_conv_mode != NULL_CONV)
      {
         if ( pSignal->chan == SIGNAL1 ) s_signal = uECD_Out_Hi1;
         else s_signal = uECD_Out_Hi2;
      }
      #else
      switch ( (BIT8)pSignal->sig_conv_mode )
      {
        case CONV_uECD_LIN:
           s_signal = LinUECD( UECD_TBL, s_signal );
           pSignal->conv_analog = s_signal; /* store data for later use.  */
           break;

        case CONV_uECD_TEST:
           /* Scale the data for the uECD to be in units of Hz.  The uECD */
           /* board has units of 2.5 Hz/display count for unlinearized    */
           /* data.                                                       */

           s_signal= SignedQuadWordMultiplyDivide( s_signal, 25, 10);
           break;

        case CONV_LDID_LIN:
           s_signal = LinLDID( LDID_TBL, s_signal );
           pSignal->conv_analog = s_signal; /* store data for later use.  */
           break;

        case CONV_LDID_TEST:
           /* Scale the data for the LDID  to be in units of pA.  The LDID  */
           /* board has units of ??????/display count for unlinearized      */
           /* data.                                                         */

/* REVISIT s_signal= SignedQuadWordMultiplyDivide( s_signal, 25, 10);       */
           break;

        default:             /* do nothing */
           break;
      }
      #endif

      /* For a detector type signal from the Signal DSP we want to check and  */
      /* see if we should apply SCC, Single Column Compensation.              */
      if ( pSignal->ccomp_mode )
      {
         /* Apply SCC Compensation */
         s_signal = ApplySCC_32( s_signal );

         if ( pSignal->signal == TEST_PLOT_SIGNAL )
         {
            s_signal /= 256;
         }
      }
   }
   else
   /* Get the data from alternate source */
   {
      s_signal = pSignal->plot_out;
   }

   if ( (pSignal->zero_attn_on_off & RESUM2_RESUME_MASK) == RESUM2_RESUME_MASK )
   {

       /*
          pSignal->zero = ( ( pSignal->zero_attn_on_off & ZERO_ON_MASK ) ? pSignal->zero : 0  ) +
                          s_signal - ((pSignal->chan == SIGNAL1) ? aECD_Out_Hi1 : aECD_Out_Hi2 );
       */

       if ( (pSignal->zero_attn_on_off & ZERO_ON_MASK) == 0)
       {
        pSignal->zero = 0 ;
       }

       pSignal->zero += s_signal - ((pSignal->chan == SIGNAL1) ? aECD_Out_Hi1 : aECD_Out_Hi2 );

       *((pSignal->chan == SIGNAL1) ? &aECD_Out_Hi1 : &aECD_Out_Hi2 ) = s_signal;

       pSignal->zero_attn_on_off &=  RESUMEX_FRZ_OFF_MSK;

       pSignal->zero_attn_on_off |= ZERO_ON_MASK;

       /*
       pSignal->bunch_count  = 0;
       pSignal->bunch_sum.lo = 0;
       pSignal->bunch_sum.hi = 0;
       */
       pSignal->bunch_reset = TRUE;  /* ?????????????????????? */

   }

   if ( pSignal->zero_attn_on_off & RESUMEX_FRZ_ON_MSK  )
   {
      s_signal = ((pSignal->chan == SIGNAL1) ? aECD_Out_Hi1 : aECD_Out_Hi2 );
   }
   else
   {

   /* REVISIT: for uECD development ... NO !!! Now aECD_Out_HiX also used by FREEZE_SIGNAL rtt events !! */
      *((pSignal->chan == SIGNAL1) ? &aECD_Out_Hi1 : &aECD_Out_Hi2 ) = s_signal;
   /* End of REVISIT: for uECD development */

   }

   /* Filter the signal for display purposes */
   FILTER_SIGNAL( s_signal, pSignal );

   /* Monitor the signal for diagnostics */
   MONITOR_SIGNAL( s_signal, pSignal );


   /* Apply zero offset compensation if enabled. */
   if ( pSignal->zero_attn_on_off & ZERO_ON_MASK )
   {
      /* Apply Zero */
      if ( s_signal < 0 )
      {
         s_signal -= pSignal->zero;     /* subtract the zero offset  */

         /* See if there was underflow */
         if ( ( s_signal >= 0 )  && ( pSignal->zero >= 0 ) )
         {
            /* underflow occurred - the data has changed sign */
            s_signal = (INT32)MIN_SIGNED_32BIT_VALUE;
         }
      }
      else  /* signal >= 0 */
      {
         s_signal -= pSignal->zero;     /* subtract the zero offset  */

         if ( ( s_signal < 0 )  && ( pSignal->zero < 0 ) )
         {
            /* overflow occurred - the data has changed sign */
            s_signal = MAX_SIGNED_32BIT_VALUE;
         }
      }
   }  /* end Apply Zero */


   /* Apply Range */

   /* First add in the remainder from the previous range operation. */
   if ( s_signal < 0 )
   {
      s_signal += pSignal->range_rem; /* add 8-bit remainder */
   }
   else  /* signal >= 0 */
   {
      s_signal += pSignal->range_rem; /* add 8-bit remainder */

      /* See if there was overflow */
      if ( ( s_signal < 0 )  && ( pSignal->range_rem > 0 ) )
      {
         s_signal = MAX_SIGNED_32BIT_VALUE;
      }
   }

   /* Now apply the Range */
   s_temp = pSignal->range;

   if (s_temp <= 4)             /* left shift for range less than 5 */
   {
      pSignal->range_rem = 0;   /* set the remainder to zero */

      s_temp = 5 - s_temp;      /* get the left shift value */

      if ( s_signal < 0 )
      {
         for ( i = 1; i <= s_temp; i++ )
         {
            s_signal = s_signal << 1;

            if ( s_signal >= 0 )
            {
               /* Underflow occurred */
               s_signal = (INT32)MIN_SIGNED_32BIT_VALUE;
            }
         }
      }
      else
      {
         for ( i = 1; i <= s_temp; i++ )
         {
            s_signal = s_signal << 1;

            if ( s_signal < 0 )
            {
               /* Overflow occurred */
               s_signal = MAX_SIGNED_32BIT_VALUE;
            }
         }
      }
   }
   else                         /* else right shift */
   {
      s_temp -= 5;              /* get the right shift value */

      /* Get the remainder by masking off all but the bits that will be lost  */
      /* by shifting                                                          */
      pSignal->range_rem = s_signal & RANGE_REM_TABLE[s_temp];

      /* Get the ranged value */
      s_signal = s_signal >> s_temp;
   }


   /* Finally, clamp the output to 24-bit unsigned value maximum to prevent   */
   /* overflow in ATTNSignalPath and DACSignalPath, which expect 24-bit       */
   /* unsigned signal data maximum.                                           */

   if ( s_signal > MAX_24BIT_VALUE )
   {
      s_signal = MAX_24BIT_VALUE;
   }

   /* Now process DAC and ATTN signals separately */

/* ATTN Signal Path */

   ATTNSignalPath(s_signal);

/* DAC Signal Path */

   DACSignalPath(s_signal);

/* Digital Signal Path */

/* REVISIT:  make a function call for NOW!!!!!!!! */

   DigitalSignalPath( );

/* End of REVISIT:  make a function call for NOW!!!!!!!! */

}



/***********************************************************************/
/* FUNCTION:  HandleStartSignal                                        */
/* ========                                                            */
/*                                                                     */
/* PURPOSE:                                                            */
/*                                                                     */
/* RETURNED VALUE:                                                     */
/*                                                                     */
/* GLOBALS USED:                                                       */
/*                                                                     */
/* CALLS:                                                              */
/*                                                                     */
/* LIMITATIONS:                                                        */
/*                                                                     */
/***********************************************************************/

void HandleStartSignal( void )
{
   /* Process the Possible START Run signal */
   if ( Dsp_In.start_run_count )
   {
      ProcessStartSignal();
   }
}



/***********************************************************************/
/* FUNCTION:  ProcessStartSignal                                       */
/* ========                                                            */
/*                                                                     */
/* PURPOSE:                                                            */
/*                                                                     */
/* RETURNED VALUE:                                                     */
/*                                                                     */
/* GLOBALS USED:                                                       */
/*                                                                     */
/* CALLS:                                                              */
/*                                                                     */
/* LIMITATIONS:                                                        */
/*                                                                     */
/***********************************************************************/

void ProcessStartSignal( void )
{
   U_INT8  s_position;
   U_INT16 s_interval;  /* interval between data pts */
   U_INT8  i;           /* loop counter for data count */

   /* Process the START Run signal */

   /* Check for multiple data points.  The DSP sends data at a vari- */
   /* able rate of either 20, 50, 100, 200, 500, or 1000 Hz.  Since  */
   /* it sends this data at 100 Hz, there may be 0-10 data points    */
   /* available.                                                     */

   if (pSignal->dsp_data->sig_count > 1)
   {
      /* MULTIPLE DATA POINTS */
      /* Insert START marker in the data if applicable. */

      /* Calculate position to insert the START run marker.  This may*/
      /* require inserting it between data points since more than    */
      /* one data point was recieved.                                */
      /* position = start run count/interval between pts +1          */

      /* interval between data points */
      s_interval = 160/pSignal->dsp_data->sig_count;

      /* Calculate the new start run count:                          */
      /*    # of time ticks between data points (interval) -         */
      /*    ( start count MOD interval )                             */
      pSignal->start_run_count = s_interval -
                                 Dsp_In.start_run_count % s_interval;

      s_position = (Dsp_In.start_run_count-1)/s_interval + 1;

      /* See if the marker is positioned at the last data pt. IF so  */
      /* THEN wait till next time to insert it at the beginning of   */
      /* the data stream.  This is because we have to send a data pt.*/
      /* after the START MARKER to the CompressAndStore since it uses*/
      /* the marker and the next data point when formatting the data.*/

      if ( s_position < pSignal->dsp_data->sig_count )
      {

         /* Insert the data BETWEEN data points. */

         /* Move the data points down two positions to make make room*/
         /* for the START marker.                                    */
         for ( i = (U_INT8)pSignal->dsp_data->sig_count;              \
               i > (U_INT8)s_position; i-- )
         {
            /* Move the data down 2 positions */
            pSignal->dig_data[i+1] = pSignal->dig_data[i-1];
         }

         /* Now insert the START marker and start count */
         pSignal->dig_data[s_position].hi_long   = (INT32)START_SIGNAL_MARKER;
         pSignal->dig_data[s_position].lo_word   = 0;
         pSignal->dig_data[s_position+1].hi_long = pSignal->start_run_count;
         pSignal->dig_data[s_position+1].lo_word = 0;

         /* Increment signal count to account for the START marker & */
         /* start count                                              */
         pSignal->dsp_data->sig_count +=2;

         /* Check to see if we are in RUN acquisition mode.  If so then we    */
         /* "have" to transmitt only run pertinent data.  So we will          */
         /* reposition the signal data in the output buffer and decrement     */
         /* the signal count appropriately.                                   */

         if ( Acq_Mode[pSignal->chan] == RUN )
         {
            for ( i = s_position; i < pSignal->dsp_data->sig_count; i++ )
            {
               pSignal->dig_data[i-s_position] = pSignal->dig_data[i];
            }

            pSignal->dsp_data->sig_count -= s_position;
         }

         /* Clear the start run count, we are done sending out the   */
         /* START marker.                                            */
         pSignal->start_run_count = 0;

         SET_RUN_IN_PROGRESS();

      }   /* end "insert START between data points" */
      else
      {
         pSignal->run_state = START_PENDING;
      }
   }   /* End for MULTIPLE DATA POINTS */
   else
   {
   /* SINGLE DATA POINT -or- NONE */

      pSignal->start_run_count = TIME_INTERVAL_100HZ -
                                 Dsp_In.start_run_count;

      pSignal->run_state = START_PENDING;

   }
}



/***********************************************************************/
/* FUNCTION:  HandlePendingStartSignal                                 */
/* ========                                                            */
/*                                                                     */
/* PURPOSE:                                                            */
/*                                                                     */
/* RETURNED VALUE:                                                     */
/*                                                                     */
/* GLOBALS USED:                                                       */
/*                                                                     */
/* CALLS:                                                              */
/*                                                                     */
/* LIMITATIONS:                                                        */
/*                                                                     */
/***********************************************************************/

void HandlePendingStartSignal( void )
{
   U_INT8 i;

   /* If the start run count has not been cleared then we  have not  */
   /* received the first data point in the run so we need to see if  */
   /* data is available.                                             */

   if ( pSignal->dsp_data->sig_count )
   {
      for ( i = (U_INT8)pSignal->dsp_data->sig_count; i>=1; i-- )
      {
         pSignal->dig_data[i+1] = pSignal->dig_data[i-1];
      }

      /* Put START marker before data point(s). */
      pSignal->dig_data[0].hi_long = (INT32)START_SIGNAL_MARKER;
      pSignal->dig_data[0].lo_word = 0;
      pSignal->dig_data[1].hi_long = pSignal->start_run_count;
      pSignal->dig_data[1].lo_word = 0;

      SET_RUN_IN_PROGRESS();

      /* Increment the Signal Count, sig_count to account for the    */
      /* START marker and start count.                               */
      pSignal->dsp_data->sig_count +=2;

      /* Clear the start run count */
      pSignal->start_run_count = 0;
   }
   else
   {
      /* No data available so add a 100Hz time count */
      pSignal->start_run_count += TIME_INTERVAL_100HZ;
   }
}



/***********************************************************************/
/* FUNCTION:  HandleStopSignal                                         */
/* ========                                                            */
/*                                                                     */
/* PURPOSE:  To insert a STOP or START_STOP marker in the data stream  */
/*           if a stop request has been made.                          */
/*                                                                     */
/* RETURNED VALUE:                                                     */
/*                                                                     */
/* GLOBALS USED:                                                       */
/*                                                                     */
/* CALLS:                                                              */
/*                                                                     */
/* LIMITATIONS:                                                        */
/*                                                                     */
/***********************************************************************/

void HandleStopSignal( void )
{
   /* Check for a STOP run marker request */
   if ( pSignal->stop_run_marker == TRUE )
   {
      ProcessStopSignal();

   }
}



/***********************************************************************/
/* FUNCTION:  ProcessStopSignal                                        */
/* ========                                                            */
/*                                                                     */
/* PURPOSE:                                                            */
/*                                                                     */
/* RETURNED VALUE:                                                     */
/*                                                                     */
/* GLOBALS USED:                                                       */
/*                                                                     */
/* CALLS:                                                              */
/*                                                                     */
/* LIMITATIONS:                                                        */
/*                                                                     */
/***********************************************************************/

void ProcessStopSignal( void )
{
   switch( pSignal->run_state )
   {
      case RUN_IN_PROGRESS:

         /* Append STOP after last data point */
         pSignal->dig_data[pSignal->dsp_data->sig_count].hi_long =
                                                 (INT32)STOP_SIGNAL_MARKER;
         pSignal->dig_data[pSignal->dsp_data->sig_count].lo_word = 0;

         break;

      case START_PENDING:
         /* Append START_STOP after last data point */
         pSignal->dig_data[pSignal->dsp_data->sig_count].hi_long =
                                           (INT32)START_STOP_SIGNAL_MARKER;
         pSignal->dig_data[pSignal->dsp_data->sig_count].lo_word = 0;
         break;

      default:
         SetNewException( INVALID_SIG_COUNT, 0, 0 );
   }

   pSignal->dsp_data->sig_count++;

   pSignal->run_state = NOT_IN_RUN;
   pSignal->stop_run_marker = FALSE;

}
